#include "map.h"

unsigned int UNIQUE_TILE_ID = 0;

CMap::~CMap()
{

	m_vTiles.clear();
	m_vRegions.clear();
	
}

CMapRegion::~CMapRegion()
{
	
	if( m_pFBO )
		delete m_pFBO;
	
}

CMapRegion::CMapRegion()
{
	
	m_pFBO = NULL;
	
}

void CMapRegion::SetRegionData( CFrameBufferObject * fbo, Vector2D point, Vector2D size )
{
	
	m_pFBO = fbo;
	m_Pos = point;
	m_Size = size;
	
}

void CTile::HandleEntityCollision( CEntity * e )
{
	
	if( !e )
		return;
	
	if( m_TileType == 2 )
	{
		
		if( e->IsPlayer() ) 
		{
			
			if( m_TileName.substr( 0, 2 ) == "::" )
			{
				
				std::string map = "maps/" + m_TileName.substr( 2 ) + ".map";
				
				m_pEntityInterface->ScheduleLoadMap( map );
				
			}
			
			if( m_TileName.substr( 0, 1 ) == "=" )
			{
				
				std::string func = m_TileName.substr( 1 );
				
				m_pEntityInterface->CallLevelHook( func.c_str() );
				
			}
			
		}
		
	}
	
}

bool CMap::EntityCollidingWithMap( CEntity * e, CCollisionReport & cr )
{
	
	if( !e || !e->GetCollisionBox() || !e->GetCollisionBox()->Enabled() )
		return false;

	for( std::vector< CCollisionBox * >::iterator iter = m_vCollisionMap.begin();
		 iter != m_vCollisionMap.end(); iter++ )
		{
			
			CCollisionData cd;
			
			if( e->IsCollidingWith( ( *iter ), cd ) )
			{
				
			//	int i = ( *iter )->GetSpecialMapIndex();
				
			//	CTile * tile = m_vTiles[i];
			//	tile->HandleEntityCollision( e );
				
				cr.m_CollisionData.push_back( cd );
				
				if( cr.count() >= cr.m_MaxData )
					break;
				
			}
				
			
		}

	return ( cr.count() > 0 );
	
}

void CMap::DrawAndCull( const Vector2D & campos )
{
	
	
	for( std::vector< CTile * >::iterator iter = m_vTiles.begin();
		 iter != m_vTiles.end(); iter++ )
		{
		
			Vector2D p = ( *iter )->GetPos();
			
			p.x -= campos.x;
			p.y -= campos.y;
			
			if( p.x > 0.0 && p.y > -10.0 && p.x < SCREEN_WIDTH && p.y < SCREEN_HEIGHT )
				( *iter )->Draw();
			
		}
	
}

void CMapRegion::Draw( const Vector2D & cam )
{
	
	PUSH_MATRIX;
	
	Draw::Scale( 1.0f, -1.0f, 1.0f );
	
	m_pFBO->BindTexture();
	
	Draw::TexturedQuad( m_Pos.x, -m_Pos.y - 600, 800, 600 );

	POP_MATRIX;	
	
}

void CMap::DrawFrameBufferObjects( const Vector2D & cam )
{
	
	Draw::SetCull( true );

	for( std::vector< CMapRegion * >::iterator iter = m_vRegions.begin();
		iter != m_vRegions.end(); iter++ )
		{
			
			( *iter )->Draw( cam );
			
		}
		
	Draw::SetCull( false );
	
}

void CMap::DrawOutline()
{
	
	glDisable( GL_TEXTURE_2D );
	
	glColor4f( .3f, .3f, .3f, 1.0f );
	
	glPushMatrix();
	
	Draw::Quad( -2, -2, 0, m_PixelWidth + 4, 2 );
	Draw::Quad( -2, -2, 0, 4, m_PixelHeight + 4 );
	Draw::Quad( m_PixelWidth, -2, 0, 2, m_PixelHeight + 4 );
	Draw::Quad( -2, m_PixelHeight, 0, m_PixelWidth + 4, 2 );
	
	glPopMatrix();
	
	glEnable( GL_TEXTURE_2D );
	glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
	
}

void CMap::Draw()
{
	
	for( std::vector< CTile * >::iterator iter = m_vTiles.begin();
		 iter != m_vTiles.end(); iter++ )
		{
			
			( *iter )->Draw();
			
		}
	
}

void CMap::DrawTilesAt( Vector2D pos, Vector2D size )
{

	for( std::vector< CTile * >::iterator iter = m_vTiles.begin();
		 iter != m_vTiles.end(); iter++ )
		{
		
			if( ( *iter )->GetPos().x >= pos.x && ( *iter )->GetPos().y >= pos.y &&
				( *iter )->GetPos().x < pos.x + size.x && ( *iter )->GetPos().y < pos.y + size.y )
			{
	
				( *iter )->Draw();
				
			}
			
			
		}	
	
}

void CMap::Load( std::string dir )
{

	std::ifstream file( dir.c_str() );

	if( file.bad() )
		return;
	
	std::map< int, std::string> texFiles;
	int readingStage = 0;
	
	m_PixelWidth = m_PixelHeight = 0;
	
	m_TopLeftPoint.SetXY( -1, -1 );
	
	file >> m_MapVersion;
	file >> m_MapWidth >> m_MapHeight;

	while( !file.eof() )
	{
		
		if( readingStage == 0 )
		{
			
			int temp;
			std::string texfile;
			
			file >> temp;
			
			if( temp == -991 )
				readingStage = 1;
			else
			{
				
				file >> texfile;
				
				texFiles[temp] = texfile;
				
			}
			
		} else if( readingStage == 1 )
		{
			
			int texid;
			
			file >> texid;
			
			if( texid == -992 )
			{
				
				readingStage = 2;
				
			} else
			{
				
				int id, type;
				double x, y, w, h;
				int r, g, b;
				std::string name;
				double s1, t1, s2, t2;
			
				file >> id >> type >> name >> x >> y >> w >> h >> r >> g >> b >> s1 >> t1 >> s2 >> t2;
				
				CMaterial * mat = NULL;
				
				if( texid >= 0 )
				{
				
					
					if( ( mat = m_pEntityInterface->Graphics()->Find( texFiles[texid] ) ) == NULL )
						mat = m_pEntityInterface->Graphics()->LoadMaterial( texFiles[texid] );
					
				}
				
				//if( mat )
				{
					
					if( texid >= 0 )
					{
						
						if( x + w > m_PixelWidth )
							m_PixelWidth = x + w;
						
						if( y + h > m_PixelHeight )
							m_PixelHeight = y + h;
						
						if( m_TopLeftPoint.x > x || m_TopLeftPoint.x < 0 ) 
						{
							
							m_TopLeftPoint.x = x;
							
						}
						
						if( m_TopLeftPoint.y > y || m_TopLeftPoint.y < 0 ) 
						{
							
							m_TopLeftPoint.y = y;
							
						}					
						
						
					}
					
					CTile * t = new CTile;
					
					t->SetName( name );
					t->SetType( type );
					
					t->SetST( s1, t1, s2, t2 );
					
					t->SetUniqueID( id );
					t->SetPos( x, y );
					
					t->SetColor( r / 255.0, g / 255.0, b / 255.0, 1.0 );
					
					t->SetEntityInterface( m_pEntityInterface );
					
					if( mat )
						t->AddSprite( mat, true );
					
					t->SetSizeOverride( w, h );
					
					t->SyncCollisionBoxPos();
					/*
					 * if( type == 1 || type == 2 )
					 * {
					 *	
					 *	if( type == 1 && mat )
					 *		t->FitCollisionBoxToSprite2( 0, offsetx, offsety, xmul, ymul );
					 *	else
					 *		t->FitCollisionBoxToSprite2( -1, offsetx, offsety, xmul, ymul );
					 *		
					 *	t->GetCollisionBox()->SetSpecialMapIndex( m_vTiles.size() );
					 *	
					 *	m_vCollisionMap.push_back( t->GetCollisionBox() );
					 *	
					 }*/
					
					m_vTiles.push_back( t );
					
				}
					
			}
			
		} else
		{
			
			int x[3], y[3];
			
			file >> x[0];
			
			if( x[0] == -993 )
				break;
			else
			{
				
				file >> y[0];
				
				for( int j = 1; j < 3; j++ )
				{
					
					file >> x[j] >> y[j];
					
				}
				
				CCollisionBox * c = new CCollisionBox;
				
				c->SetCollisionType( CBOX_TRIANGLE );
				
				for( int j = 0; j < 3; j++ )
					c->SetPoint( j, x[j], y[j] );
				
				c->CalculateSATPoints();
				
				c->SetEnabled( true );
				
				m_vCollisionMap.push_back( c );
				
			}
			
		}
		
	}
	
	file.close();
	
	int horiz_regions = m_MapWidth / REGION_W + ( ( m_MapWidth % REGION_W )? 1 : 0 );
	int vert_regions = m_MapHeight / REGION_H + ( ( m_MapHeight % REGION_H )? 1 : 0 );
	
	Vector2D regionsize;
	regionsize.SetXY( REGION_W * REGION_TILESIZE, REGION_H * REGION_TILESIZE );

	for( int y = 0; y < vert_regions; y++ )
	{
		
		for( int x = 0; x < horiz_regions; x++ )
		{
			
			CFrameBufferObject * fbo = new CFrameBufferObject( 800, 600 );

			fbo->BindFrameBufferObject();
			
			CLEAR_BUFFER;
	
			Vector2D point;
			point.SetXY( x * REGION_W * REGION_TILESIZE, y * REGION_H * REGION_TILESIZE );
		
			Draw::Translate( -point.x, -point.y, 0.0f );
			DrawTilesAt( point, regionsize );

			CMapRegion * region = new CMapRegion;
			region->SetRegionData( fbo, point, regionsize );
			m_vRegions.push_back( region );

			fbo->UnbindFrameBufferObject();

		}
		
	}
	
	

}